package sg.edu.nus.iss.jass.datastore;

import java.lang.reflect.Type;
import java.util.List;

import sg.edu.nus.iss.jass.datastore.exception.DataStoreException;

/**
 * <p>This interface defines general operations to store object and retrieve object from some kind of storage</p>
 * Only child class of {@link BaseDTO} can be the target of these operations. 
 * 
 * @author WANG DAYONG
 * 
 */
public interface IDataStore {

	/**
	 * <p>To load object of specified type that matches given id</p>
	 * 
	 * @param <T>
	 *            Subclass of {@link BaseDTO}
	 * @param type
	 *            A type of {@link BaseDTO} is to be loaded
	 * @param id
	 *            Retrieval condition that the record must match
	 * @return <T extends BaseDTO> The matched record,
	 * 			if no record found, return null
	 *         
	 * @throws DataStoreException
	 * 			if encountering error while loading object
	 */
	public <T extends BaseDTO> T loadObjectByID(Type type, String id) throws DataStoreException;

	/**
	 * <p>To load all the objects of specified type</p>
	 * 
	 * @param <T>
	 *            Subclass of {@link BaseDTO}
	 * @param type
	 *             A type of {@link BaseDTO} is to be loaded
	 * @return List<T extends BaseDTO> All matched objects of specified type,
	 *         return <code>null</code> if no record found
	 * @throws DataStoreException
	 * 		   if encountering error while loading object
	 */
	public <T extends BaseDTO> List<T> loadObjectsByType(Type type) throws DataStoreException;

	/**
	 * <p>To batch load objects of specified type that match given collection of id</p>
	 * 
	 * @param <T>
	 *            Subclass of {@link BaseDTO}
	 * @param type
	 *             A type of {@link BaseDTO} is to be loaded
	 * @param id
	 *            Retrieval condition that the record must match
	 * @return List<T extends BaseDTO> All matched objects of specified type,
	 *         	return <code>null</code>, if no record found
	 * @throws DataStoreException
	 * 			if encountering error while loading object
	 */
	public <T extends BaseDTO> List<T> loadObjectsByIDs(Type type, String... id) throws DataStoreException;

	/**
	 * <p>To batch load objects of specified type that match selector passed in.</p> 
	 * selector is used to search on non-id field of the object. Please refer to {@link ISelector}
	 * 
	 * @param <T>
	 *            Subclass of {@link BaseDTO}
	 * @param type
	 *             A type of {@link BaseDTO} is to be loaded
	 * @param selector
	 *            The criteria to filter the return result list, also see {@link ISelector}
	 * @return Matched objects of specified type
	 * @throws DataStoreException
	 * 			if encountering error while loading data
	 */
	public <T extends BaseDTO> List<T> loadObjectsBySelector(Type type, ISelector selector) throws DataStoreException;


	/**
	 * <p>To save the given object</p>
	 * <li>If same record is found in storage by id of given object, this object will be updated to storage.</li>
	 * <li>If the id of given object is empty or null, a new record will be inserted to storage with generated id.</li>
	 * <li>If the value of id is set, but the object of given id can't find in storage, DataStorageException is thrown.</li> 
	 * <li>All update operation will check the version, if the version is changed, DataStorageException is thrown to show the
	 * same record has been modified by others.</li>
	 * 
	 * @param <T>
	 *            Subclass of {@link BaseDTO}
	 * @param object
	 *            The object is to be saved
	 * @throws DataStoreException
	 * 			  <li>If the value of id is set, but the id of given object can't be found</li>
	 * 			  <li>If the value of version is changed when performing update operation.</li>
	 *            <li>If encountering error while saving object</li> 	 
	 */
	public <T extends BaseDTO> void saveObject(T object) throws DataStoreException;

	/**
	 *  <p>To save the given collection of objects</p>
	 * <li>If same record is found in storage by given id, the record will be updated by the given record.</li>
	 * <li>If the value of id is empty or null, a new record will be inserted to storage with generated id</li>
	 * <li>If the value of id is set, but the object of given id can't find in storage, DataStorageException is thrown.</li> 
	 * <li>All update operation will check the version, if the version is changed, DataStorageException is thrown to show the
	 * same record has been modified by others.</li>
	 * 
	 * @param <T>
	 *            Subclass of {@link BaseDTO}
	 * @param list
	 *            The collection of objects are to be saved
	 * @throws DataStoreException
	 * 			  <li>If the value of id is set, but the id of given object can't be found</li>
	 * 			  <li>If the value of version is changed when performing update operation.</li>
	 *            <li>If encountering error when saving object</li> 
	 */
	public <T extends BaseDTO> void saveObjects(List<T> list) throws DataStoreException;

	/**
	 * <p>To delete the record of specified type that matches the given id</p>
	 * 
	 * @param <T>
	 *            Subclass of {@link BaseDTO}
	 * @param type
	 *             A type of {@link BaseDTO} is to be deleted 
	 * @param id
	 *            Deletion condition that the record must match
	 * @throws DataStoreException
	 *            <li>If the id belonging to specified type is not found</li>
	 *            <li>If encountering error when persistent the changes</li>
	 */
	public <T extends BaseDTO> void deleteObjectByID(Type type, String id) throws DataStoreException;

	/**
	 * </p>To batch delete records of given collection of objects/p>
	 * 
	 * @param <T>
	 *            Subclass of {@link BaseDTO}
	 * @param list
	 *            Collection of objects are to be deleted
	 * @throws DataStoreException
	 * 			  <li>If id of any given object in list is not found in storage.</li>
	 *            <li>If encountering error while saving changes</li>
	 */
	public <T extends BaseDTO> void deleteObjects(List<T> list) throws DataStoreException;

	/**
	 * It's not implemented in current version
	 * For test purpose
	 * @throws DataStoreException
	 */
	@Deprecated
	public void flush() throws DataStoreException;

	/**
	 * <p>Obtain transaction</p>
	 * 
	 * @return Transaction Refer to {@link Transaction}
	 * @throws DataStoreException
	 * 			if the implementation does not support transaction
	 */
	public Transaction getTransaction() throws DataStoreException;
}
